package mobile.game.core.support;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.quartz.TriggerUtils;
import org.quartz.impl.triggers.CronTriggerImpl;

/**
 * @author g
 *
 * 时间、日期处理相关
 */
public class TimeUtils {
	/** 秒 */
	public static final long SEC = 1000L;
	/** 分 */
	public static final long MIN = 60 * SEC;
	/** 小时 */
	public static final long HOUR = 60 * MIN;
	/** 天 */
	public static final long DAY = 24 * HOUR;
	/** 年 */
	public static final long YEAR = 365 * DAY;
	/** 十年(最大持续时间，可以当永久时间用，游戏运营不了十年的) */
	public static final long TEN_YEAR = 10 * YEAR;
	
	/**
	 * 格式化时间戳
	 * @param value
	 * @param pattern
	 * @return
	 */
	public static String formatTime(long timestamp, String pattern) {
		SimpleDateFormat format = new SimpleDateFormat(pattern);

		return format.format(new Date(timestamp));
	}
	
	/**
	 * 将日期字符串转化为毫秒数
	 * @param dateTime
	 * @return
	 */
	public static long formatTimeToLong(String dateTime){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date;
		try {
			date = sdf.parse(dateTime);
			return date.getTime();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	/**
	 * 将毫秒数转化为日期(毫秒--->yyyy-MM-dd HH:mm:ss)
	 * @param time (单位:毫秒)
	 * @return
	 */
	public static String formatTimeToDate(long time){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = new Date();
		date.setTime(time);
		return sdf.format(date);
	}
	
	/**
	 * 将毫秒数转化为日期精确到小时(毫秒--->yyyy-MM-dd HH)
	 * @param time (单位:毫秒)
	 * @return
	 */
	public static String formatTimeToDateHH(long time){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH");
		Date date = new Date();
		date.setTime(time);
		return sdf.format(date);
	}
	
	/**
	 * 根据时分秒配置 获取今天配置时间点
	 * @param suffix
	 * @return
	 */
	public static long formatDateStr(String dateStr, String pattern) {
		try {
			SimpleDateFormat bartDateFormat = new SimpleDateFormat(pattern);
			
			return bartDateFormat.parse(dateStr).getTime();
		} catch (Exception ex) {
			throw new SysException(ex);
		}
	}
	
	/**
	 * 两个时间戳相差的天数
	 * @param a
	 * @param b
	 * @return
	 */
	public static int getDaysBetween(long ta, long tb) {
		Calendar a = Calendar.getInstance();
		a.setTimeInMillis(ta);
		Calendar b = Calendar.getInstance();
		b.setTimeInMillis(tb);
		
		if (a.after(b)) {
			Calendar swap = a;
			a = b;
			b = swap;
		}
		
		int days = b.get(Calendar.DAY_OF_YEAR) - a.get(Calendar.DAY_OF_YEAR);
		int y2 = b.get(Calendar.YEAR);
		if (a.get(Calendar.YEAR) != y2) {
			a = (Calendar) a.clone();
			do {
				days += a.getActualMaximum(Calendar.DAY_OF_YEAR);
				a.add(Calendar.YEAR, 1);
			} while (a.get(Calendar.YEAR) != y2);
		}
		return days;
	}
	
	/**
	 * 是否在时间区间内
	 * 
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	public static boolean isBetween(long now, String startTime, String endTime) {
		long start = 0, end = 0;
		if (!StringUtils.isEmpty(startTime) || !StringUtils.isEmpty(endTime)) {
			try {
				start = formatDateStr(startTime, "yyyy-MM-dd HH:mm:ss");
				end = formatDateStr(endTime, "yyyy-MM-dd HH:mm:ss");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return isBetween(now, start, end);
	}
	
//	public static boolean isBetween(long now, String startTime, String endTime, ){
//		
//	}
	
	public static boolean isBetween(long now, long start, long end) {
		try {
			if (start > 0 && now < start) {
				return false;
			}
			if (end > 0 && now > end) {
				return false;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return true;
	}

	/**
	 * 是否是同一天
	 * @param ta
	 * @param tb
	 * @return
	 */
	public static boolean isSameDay(long ta, long tb) {
		return formatTime(ta, "yyyyMMdd").equals(formatTime(tb, "yyyyMMdd"));
	}

	/**
	 * 是否是同一周
	 * @param ta
	 * @param tb
	 * @return
	 */
	public static boolean isSameWeek(long ta, long tb) {
		return getTimeBeginOfWeek(ta) == getTimeBeginOfWeek(tb);
	}

	/**
	 * 是否是同一月
	 * @param ta
	 * @param tb
	 * @return
	 */
	public static boolean isSameMonth(long ta, long tb) {
		return getTimeBeginOfMonth(ta) == getTimeBeginOfMonth(tb);
	}
	
	/**
	 * 获取给定时间当前凌晨的时间对象
	 * @param time 取当天凌晨的话传入 System.currentTimeMillis() 即可
	 * @return
	 */
	public static long getTimeBeginOfToday(long time) {
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);
		ca.set(Calendar.HOUR_OF_DAY, 0);
		ca.set(Calendar.MINUTE, 0);
		ca.set(Calendar.SECOND, 0);
		ca.set(Calendar.MILLISECOND, 0);
		
		return ca.getTimeInMillis();
	}
	
	/**
	 * 获取给定时间本周一的时间对象
	 * @param time 取当天凌晨的话传入 System.currentTimeMillis() 即可
	 * @return
	 */
	public static long getTimeBeginOfWeek(long time) {
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);
		
		//当今天是星期天的时候，需要特殊处理，因为星期天是按照这个星期第一天算的，而我们不是这么需要的
		long timeCheck = 0;
		if(ca.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			timeCheck = TimeUtils.DAY * 7;
		}
		
		ca.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		ca.set(Calendar.HOUR_OF_DAY, 0);
		ca.set(Calendar.MINUTE, 0);
		ca.set(Calendar.SECOND, 0);
		ca.set(Calendar.MILLISECOND, 0);
		
		return ca.getTimeInMillis() - timeCheck;
	}
	
	/**
	 * 获取本月第一天0点
	 * @param time 取当天凌晨的话传入 System.currentTimeMillis() 即可
	 * @return
	 */
	public static long getTimeBeginOfMonth(long time) {
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);
		
		ca.set(Calendar.DAY_OF_MONTH, 1);
		ca.set(Calendar.HOUR_OF_DAY, 0);
		ca.set(Calendar.MINUTE, 0);
		ca.set(Calendar.SECOND, 0);
		ca.set(Calendar.MILLISECOND, 0);
		
		return ca.getTimeInMillis();
	}

	/**
	 * 根据当前时间，获取小时数 24小时格式
	 * @param time 当天的时间 
	 * @return
	 */
	public static int getHourOfTime(long time) {
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);		
		return ca.get(Calendar.HOUR_OF_DAY);
	}
	
	public static int getMinuteOfTime(long time) {
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);		
		return ca.get(Calendar.MINUTE);
	}
	
	public static int getSecondOfTime(long time) {
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);		
		return ca.get(Calendar.SECOND);
	}
	
	/**
	 * 根据当前时间，获取是星期几。周日是1，周6是7
	 * @param time
	 * @return
	 */
	public static int getWeekDayOfTime(long time){
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);		
		return ca.get(Calendar.DAY_OF_WEEK);
	}
	
	/**
	 * 判断现在的时间是否在某个时间段范围内
	 * @param fromHour
	 * @param fromMin
	 * @param toHour
	 * @param fromMin
	 * @return
	 */
	public static boolean isTimeBetween(int fromHour, int fromMin, int toHour, int toMin){
	    Calendar from = Calendar.getInstance();
	    from.set(Calendar.HOUR_OF_DAY, fromHour);
	    from.set(Calendar.MINUTE, fromMin);
	    from.set(Calendar.SECOND, 0);
	    from.set(Calendar.MILLISECOND, 0);
	    
	    Calendar to = Calendar.getInstance();
	    to.set(Calendar.HOUR_OF_DAY, toHour);
	    to.set(Calendar.MINUTE, toMin);
	    to.set(Calendar.SECOND, 0);
	    to.set(Calendar.MILLISECOND, 0);
	    
	    long now = System.currentTimeMillis();
	    
	    return now >= from.getTimeInMillis() && now < to.getTimeInMillis(); 
	}
	
	/**
	 * 判断是否是一周的星期几
	 * @param Calendar.MONDAY.... (周日至周六:  1 2 3 4 5 6 7)
	 * @return
	 */
	public static boolean isDayOfWeek(int day){
		Calendar cal = Calendar.getInstance();
		return cal.get(Calendar.DAY_OF_WEEK) == day;
	}
	
	/**
	 * 判断是否是一周的某一天
	 * @param millis 毫秒数
	 * @param day (周日至周六:  1 2 3 4 5 6 7)
	 * @return
	 */
	public static boolean isDayOfWeek(long millis, int day){
		Calendar cal = Calendar.getInstance();
	    cal.setTimeInMillis(millis);
		return cal.get(Calendar.DAY_OF_WEEK) == day;
	}
	
	/**
	 * @param days 1-7  周一~周日
	 * @return 1-7  周日~周一
	 */
	public static int[] getQuartzDayOffWeek(int days[]){		
		int len = days.length;
		int[] result = new int[len];
		for(int i=0; i < len; i++){
			result[i] = days[i] == 7 ? 1 : days[i] + 1;
 		}
		
		return result;
	}
	
	/**
	 * 根据参数获取quartz的执行时间格式
	 * @param day 注意:!!!!!!quartz cron中 周日至周六的数字是  1-7
	 * @param hour
	 * @param min
	 * @param second
	 * @return 如: 每周1,3,5 12:30 执行schedule 0 30 12 ? * 2,4,6 *
	 */
	public static String getQuartzCron(int[] day, int hour, int min, int second){
		
		//0 30 12 ? * 2,4,6 *
		StringBuilder cron = new StringBuilder();
		
		if(second !=-1){
			cron.append(second + " ");
		}else{
			cron.append("* ");
		}
		
		if(min !=-1){
			cron.append(min + " ");
		}else{
			cron.append("* ");
		}
		
		if(hour != -1){
			cron.append(hour +" ");
		}else{
			cron.append("* ");
		}
		cron.append("? ");
		cron.append("* ");
		
		if(day.length > 0 && day[0]!=-1){
			for(int i=0; i< day.length; i++){
				if(i > 0){
					cron.append(",");
				}
				cron.append(day[i]);
			}
			cron.append(" ");
		}else{
			cron.append("* ");
		}
		cron.append("* ");
		return cron.toString();
	}
	
	/**
	 * 根据cron表达式计算出最近1次的执行具体时间
	 * 
	 * @param cron 时间表达式
	 * @param day 需要计算的时间区间（可以为负数）
	 * 
	 * @return
	 */
	public static Date lastFromCron(String cron, int day) {
		if (day == 0) {
			return null;
		}
		
		try {
			CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
			cronTriggerImpl.setCronExpression(cron);// 这里写要准备猜测的cron表达式
			
			Calendar calendar = Calendar.getInstance();
			Date now = calendar.getTime();
			
			// 设置统计区间
			calendar.add(Calendar.DAY_OF_MONTH, day);
			List<Date> dates = TriggerUtils.computeFireTimesBetween(
					cronTriggerImpl, null, now, calendar.getTime());
			if (dates == null || dates.size() <= 0) {
				return null;
			}
			
			if (day < 0) {
				return dates.get(dates.size() - 1);
			}else{
				return dates.get(0);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 从指定时间开始已经执行了几次
	 * 
	 * @param cron
	 * @param start
	 * @return
	 */
	public static int countFromCron(String cron, String start) {
		try {
			CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
			cronTriggerImpl.setCronExpression(cron);// 这里写要准备猜测的cron表达式
			
			Calendar calendar = Calendar.getInstance();
			Date now = calendar.getTime();
			
			calendar.setTimeInMillis(formatTimeToLong(start));
			List<Date> dates = TriggerUtils.computeFireTimesBetween(
					cronTriggerImpl, null, calendar.getTime(), now);
			if (dates == null || dates.size() <= 0) {
				return 0;
			}

			return dates.size();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	/**
	 * 获取当天某时某分某秒时间戳
	 * @param time 取当天凌晨的话传入 System.currentTimeMillis() 即可
	 * @return
	 */
	public static long getTimeinOfTodaySomeTime(long time , int hour , int minute , int second) {
		Calendar ca = Calendar.getInstance();
		ca.setTimeInMillis(time);
		ca.set(Calendar.HOUR_OF_DAY, hour);
		ca.set(Calendar.MINUTE, minute);
		ca.set(Calendar.SECOND, second);
		ca.set(Calendar.MILLISECOND, 0);
		
		return ca.getTimeInMillis();
	}
}